#include <string>
#include <list>
#include <queue>

using namespace std;

class Message;
class Communication;

class LogicalClock : public vector<unsigned>
{
public:
	LogicalClock():vector<unsigned>(), me(0){};
	LogicalClock(unsigned total, unsigned whoami):vector<unsigned>(total, 0), me(whoami){};
	void operator++(int){(*this)[me]++;}
	void operator+=(const LogicalClock &that);
	operator string(void) const;
private:
	LogicalClock(string str);
	unsigned me;
	friend class Message;
	friend class Communication;
};

class Message
{
public:
	Message():sep("@:"){}
	int node; // dest/src node id, -1 for broadcast, -2 for server
	unsigned deliv; // time of delivery, unit is tick, 0 for server
	string data; // content of message
	operator string(void) const; // serialization of the message
	bool operator<(const Message &msg) const {return deliv > msg.deliv;}
private:
	const char *sep; // seperator
	LogicalClock ts; // timestamp, using vector logical clock
	Message(const string &str); // unserialization of a message
	friend class Communication;
};

struct Host{
	string name;
	unsigned short port;
};

class Communication
{
public:
	Communication(){}
	Communication(list<Host> allhost, bool issrv = 0, int me = -1);
	void send(Message &msg); // send a message
	int recv(Message &msg, unsigned now); // deliver a message, if delivered a new message, return -1-(size of queue after the current delivery), otherwise return the size of current queue
	void event(void){vc++;}
	const LogicalClock &clock(void){return vc;}
	unsigned count, last; // count is the count of messages received (maybe not delivered) from peers since the current time slot
private:
	LogicalClock vc; // vector logical clock
	priority_queue<Message> msgq; // message queue
	int num; // number of peers
	vector<int> sock; // socket to peers
	int srv; // socket to the server, for server itself srv == 0
	int self; // index of myself
	void server(struct addrinfo **ai); // initialization of the server
	void peer(struct addrinfo **ai); // initialization of peers
	void order(void); // know the node id of the peers of each socket
	int sendconn(const struct addrinfo *me, struct addrinfo *target); // connect to a remote process
	void recvconn(struct addrinfo **ai, int to); // get connection from remote process
};

int whoami(list<string> name); // return my index among all host names
